package org.azdroid.kit.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.text.format.DateUtils;

/**
 * HTTP相关通用方法. dai_rui_lin Email:hljdrl@gmail.com
 * */
public final class HttpHelper {
	private static final int SECOND_IN_MILLIS = (int) DateUtils.SECOND_IN_MILLIS;

	private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
	private static final String ENCODING_GZIP = "gzip";

	final public static HttpClient getHttpClient1(Context mCm) {
		final HttpParams params = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(params, 50 * 1000);
		HttpConnectionParams.setSoTimeout(params, 30 * SECOND_IN_MILLIS);
		HttpConnectionParams.setSocketBufferSize(params, 8192);
		HttpProtocolParams.setUserAgent(params, buildUserAgent(mCm));
		final DefaultHttpClient client = new DefaultHttpClient(params);
		return client;
	}

	/**
	 * Generate and return a {@link HttpClient} configured for general use,
	 * including setting an application-specific user-agent string.
	 */
	final public static HttpClient getHttpClient(Context context) {
		final HttpParams params = new BasicHttpParams();

		// Use generous timeouts for slow mobile networks
		HttpConnectionParams
				.setConnectionTimeout(params, 20 * SECOND_IN_MILLIS);
		HttpConnectionParams.setSoTimeout(params, 20 * SECOND_IN_MILLIS);

		HttpConnectionParams.setSocketBufferSize(params, 8192);
		HttpProtocolParams.setUserAgent(params, buildUserAgent(context));

		final DefaultHttpClient client = new DefaultHttpClient(params);

		client.addRequestInterceptor(new HttpRequestInterceptor() {
			public void process(HttpRequest request, HttpContext context) {
				// Add header to accept gzip content
				if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
					request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
				}
			}
		});

		client.addResponseInterceptor(new HttpResponseInterceptor() {
			public void process(HttpResponse response, HttpContext context) {
				// Inflate any responses compressed with gzip
				final HttpEntity entity = response.getEntity();
				final Header encoding = entity.getContentEncoding();
				if (encoding != null) {
					for (HeaderElement element : encoding.getElements()) {
						if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
							response.setEntity(new InflatingEntity(response
									.getEntity()));
							break;
						}
					}
				}
			}
		});

		return client;
	}

	/**
	 * Generate and return a {@link HttpClient} configured for general use,
	 * including setting an application-specific user-agent string.
	 */
	final public static HttpClient getHttpClient(ClientConnectionManager dccn,
			Context context) {
		final HttpParams params = new BasicHttpParams();

		// Use generous timeouts for slow mobile networks
		HttpConnectionParams
				.setConnectionTimeout(params, 20 * SECOND_IN_MILLIS);
		HttpConnectionParams.setSoTimeout(params, 20 * SECOND_IN_MILLIS);

		HttpConnectionParams.setSocketBufferSize(params, 8192);
		HttpProtocolParams.setUserAgent(params, buildUserAgent(context));

		final DefaultHttpClient client = new DefaultHttpClient(dccn, params);

		client.addRequestInterceptor(new HttpRequestInterceptor() {
			public void process(HttpRequest request, HttpContext context) {
				// Add header to accept gzip content
				if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
					request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
				}
			}
		});

		client.addResponseInterceptor(new HttpResponseInterceptor() {
			public void process(HttpResponse response, HttpContext context) {
				// Inflate any responses compressed with gzip
				final HttpEntity entity = response.getEntity();
				final Header encoding = entity.getContentEncoding();
				if (encoding != null) {
					for (HeaderElement element : encoding.getElements()) {
						if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
							response.setEntity(new InflatingEntity(response
									.getEntity()));
							break;
						}
					}
				}
			}
		});

		return client;
	}

	/**
	 * Build and return a user-agent string that can identify this application
	 * to remote servers. Contains the package name and version code.
	 */
	final private static String buildUserAgent(Context context) {
		try {
			final PackageManager manager = context.getPackageManager();
			final PackageInfo info = manager.getPackageInfo(
					context.getPackageName(), 0);

			// Some APIs require "(gzip)" in the user-agent string.
			return info.packageName + "/" + info.versionName + " ("
					+ info.versionCode + ") (gzip)";
		} catch (NameNotFoundException e) {
			return null;
		}
	}

	/**
	 * Simple {@link HttpEntityWrapper} that inflates the wrapped
	 * {@link HttpEntity} by passing it through {@link GZIPInputStream}.
	 */
	final private static class InflatingEntity extends HttpEntityWrapper {
		public InflatingEntity(HttpEntity wrapped) {
			super(wrapped);
		}

		@Override
		public InputStream getContent() throws IOException {
			return new GZIPInputStream(wrappedEntity.getContent());
		}

		@Override
		public long getContentLength() {
			return -1;
		}
	}

	final public static byte[] readStream(InputStream inStream)
			throws Exception {
		ByteArrayOutputStream outstream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = inStream.read(buffer)) != -1) {
			outstream.write(buffer, 0, len);
		}
		outstream.close();
		inStream.close();

		return outstream.toByteArray();
	}

	final public static byte[] getHttpData(Context context, String url)
			throws ClientProtocolException, IOException {
		byte bytes[] = null;
		final HttpClient httpClient = HttpHelper.getHttpClient(context
				.getApplicationContext());
		final HttpResponse resp = httpClient.execute(new HttpGet(url));
		final HttpEntity entity = resp.getEntity();

		final int statusCode = resp.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK || entity == null) {
			return null;
		}
		bytes = EntityUtils.toByteArray(entity);
		return bytes;
	}

	final public static String getHttpDataAsString(Context context, String url)
			throws ClientProtocolException, IOException {
		byte bytes[] = null;
		final HttpClient httpClient = HttpHelper.getHttpClient(context
				.getApplicationContext());
		final HttpResponse resp = httpClient.execute(new HttpGet(url));
		final HttpEntity entity = resp.getEntity();

		final int statusCode = resp.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK || entity == null) {
			return null;
		}
		bytes = EntityUtils.toByteArray(entity);
		if (bytes != null) {
			return new String(bytes);
		} else {
			return null;
		}
	}

	/**
	 * 
	 * */
	final public static byte[] readGZIPInputStream(InputStream inStream)
			throws IOException {
		GZIPInputStream gzipStream = new GZIPInputStream(inStream);
		ByteArrayOutputStream outstream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = gzipStream.read(buffer)) != -1) {
			outstream.write(buffer, 0, len);
		}
		outstream.close();
		inStream.close();
		return outstream.toByteArray();
	}

	final public static void writeGZIPOutputStream(OutputStream outStream,
			byte[] send) throws IOException {
		GZIPOutputStream gzipStream = new GZIPOutputStream(outStream);
		gzipStream.write(send, 0, send.length);
		Thread.yield();
		gzipStream.close();
		outStream.close();
	}

	/**
	 * 
	 * 判断本地是否联网,如果没有联网直接返回
	 * 
	 * @return true 有网络 false 没有网
	 */
	final public static boolean isNetWorkAvailable(Context context) {
		ConnectivityManager connectivity = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo info = connectivity.getActiveNetworkInfo();
		if (info == null || info.getState() != State.CONNECTED) {
			return false;
		}
		return true;
	}

	// -------------------------------------------------------------------------
	public interface GetData {
		public Serializable getData(Serializable data);
	}

	/**
	 * 
	 * @param url
	 *            连接URL
	 * @param params
	 *            Map<String,String> 参数
	 * @param encode
	 *            编码类型
	 * @return 将服务器返回的流转换为String
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String getStringFromPost(String url,
			Map<String, String> params, String encode)
			throws ClientProtocolException, IOException {

		InputStream is = getInputStreamFromPost(url, params, encode);
		if (is == null) {
			return null;
		}

		ByteArrayOutputStream os = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		try {
			for (int len = 0; (len = is.read(buffer)) != -1;) {
				os.write(buffer, 0, len);
			}
		} finally {
			is.close();
		}
		return os.toString().trim();
	}

	/**
	 * 
	 * @param url
	 *            连接URL
	 * @param params
	 *            Map<String,String> 参数
	 * @param encode
	 *            编码类型
	 * @return 返回服务器获取的数据流
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static InputStream getInputStreamFromPost(String url,
			Map<String, String> params, String encode)
			throws ClientProtocolException, IOException {
		List<NameValuePair> list = new ArrayList<NameValuePair>();
		// 将提交的数据，封装到NameValuePair中
		if (params != null && !params.isEmpty()) {
			for (Map.Entry<String, String> entry : params.entrySet()) {
				NameValuePair pair = new BasicNameValuePair(entry.getKey(),
						entry.getValue());
				list.add(pair);
			}
		}
		// 与服务器获得链接
		// 封装form表单
		UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, encode);
		// 使用post方式提交数据
		HttpPost httpPost = new HttpPost(url);
		// 设置请求的body
		httpPost.setEntity(entity);

		BasicHttpParams httpParameters = new BasicHttpParams();
		// Set the default socket timeout (SO_TIMEOUT)
		HttpConnectionParams.setConnectionTimeout(httpParameters, 40*1000);
		// in milliseconds which is the timeout for waiting for data.
		HttpConnectionParams.setSoTimeout(httpParameters, 60*1000);

		HttpClient httpClient = new DefaultHttpClient(httpParameters);

		// 获得响应的结果对象
		HttpResponse httpResponse = httpClient.execute(httpPost);
		// 获得响应的结果码
		if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
			return httpResponse.getEntity().getContent();
		}
		return null;
	}

	/**
	 * 
	 * @param url
	 *            URL
	 * @param parms
	 *            参数键值对可为空
	 * @param encode
	 *            编码
	 * @return 调用成功则返回对应的流
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	static public InputStream getInputStreamFromGet(String url,
			Map<String, String> parms, String encode)
			throws ClientProtocolException, IOException {
		StringBuffer orderBuffer = null;
		if (parms != null) {
			orderBuffer = new StringBuffer("?");
			for (Map.Entry<String, String> entry : parms.entrySet()) {
				orderBuffer.append(entry.getKey() + "="
						+ URLEncoder.encode(entry.getValue(), encode) + "&");
			}
			url += orderBuffer.substring(0, orderBuffer.length() - 2);
		}

		BasicHttpParams httpParameters = new BasicHttpParams();
		// Set the default socket timeout (SO_TIMEOUT)
		HttpConnectionParams.setConnectionTimeout(httpParameters, 40*1000);
		// in milliseconds which is the timeout for waiting for data.
		HttpConnectionParams.setSoTimeout(httpParameters, 60*1000);

		HttpClient httpClient = new DefaultHttpClient(httpParameters);

		HttpGet httpGet = new HttpGet(url);
		HttpResponse httpResponse = httpClient.execute(httpGet);
		if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
			return httpResponse.getEntity().getContent();
		}
		return null;
	}

	/**
	 * 
	 * @param url
	 *            URL
	 * @param parms
	 *            参数键值对可为空
	 * @param encode
	 *            编码
	 * @return 调用成功则返回对应的字符串
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	static public String getStringFromGet(String url,
			Map<String, String> parms, String encode)
			throws ClientProtocolException, IOException {
		InputStream is = getInputStreamFromGet(url, parms, encode);
		if (is == null) {
			return null;
		}

		ByteArrayOutputStream os = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		try {
			for (int lenght = 0; (lenght = is.read(buffer)) != -1;) {
				os.write(buffer, 0, lenght);
			}
		} finally {
			is.close();
		}
		return os.toString().trim();
	}

}
